# -*- coding: utf-8 -*-
from functools import wraps
import logging
import base64
import jsonpickle

from django.http import HttpResponse
from Crypto.Cipher import AES


LOG = logging.getLogger(__name__)
REQUEST_INFO_LOGGER = logging.getLogger("request_info")


def json_response(data=None, page=1, total_page=1, total=1, page_size=20, user_info="ok",
                  message="", success=True, paging=False):
    """
    定义API公共返回格式

    :return: An dict
    """

    if paging:
        page = {
            "page_no": page,
            "page_size": page_size,
            "total_count": total,
            "total_page": total_page
        }
    else:
        page = {}

    params = {
        "page": page,
        "user_info": user_info,
        "message": message,
        "success": success,
        "data": data
    }
    json_data = jsonpickle.dumps(params, unpicklable=False)
    return HttpResponse(json_data, content_type="application/json")


# 请求加密、解密
class AESCipher(object):
    def __init__(self):
        self.key = u"0123456789123456".encode("utf-8")
        self.iv = u"2015030120123456".encode("utf-8")

    def __pad(self, text):
        """填充方式，加密内容必须为16字节的倍数，若不足则使用self.iv进行填充"""
        text_length = len(text)
        amount_to_pad = AES.block_size - (text_length % AES.block_size)
        if amount_to_pad == 0:
            amount_to_pad = AES.block_size
        pad = chr(amount_to_pad)
        return text + pad * amount_to_pad

    def __unpad(self, text):
        pad = ord(text[-1])
        return text[:-pad]

    def encrypt(self, raw):
        """加密"""
        raw = jsonpickle.dumps(raw)
        raw = self.__pad(raw)
        if isinstance(raw, str):
            raw = raw.encode(encoding="utf-8")
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return base64.b64encode(cipher.encrypt(raw))

    def decrypt(self, enc):
        """解密"""

        # str to bytes
        if isinstance(enc, str):
            enc = enc.encode(encoding="utf-8")

        enc = base64.b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        decrypt_info = self.__unpad(cipher.decrypt(enc).decode("utf-8"))
        decrypt_obj = jsonpickle.loads(decrypt_info)
        return decrypt_obj

    def is_base64(self, enc):
        try:
            # str to bytes
            if isinstance(enc, str):
                enc = enc.encode(encoding="utf-8")

            return base64.b64encode(base64.b64decode(enc)) == enc
        except Exception:
            return False


def param_info(func):
    @wraps(func)
    def _inner(self, request, *args, **kwargs):
        LOG.info("Request function: %s " % func.__name__)
        LOG.info("Start to decrypt request param info!")
        try:

            if request.method == "POST" or request.method == 'PUT' or request.method == 'DELETE':
                if request.data.get("aesRequest"):
                    REQUEST_INFO_LOGGER.info("encrypt param info : %s" % request.data)
                    request.param_info = self.aes_cipher.decrypt(request.data.get("aesRequest"))
                else:
                    REQUEST_INFO_LOGGER.info("encrypt param info : %s" % request.data)
                    request.param_info = request.data
            elif request.method == "GET":
                REQUEST_INFO_LOGGER.info("encrypt param info : %s" % request.GET)
                request.param_info = request.GET
            else:
                request.param_info = {}
        except Exception as ex:
            response_obj = json_response(message=str(ex), user_info="Failed to decrypt !",success=False)
            LOG.error(response_obj.message)
            return response_obj
        REQUEST_INFO_LOGGER.info("decrypt param info : %s" % request.param_info)
        LOG.info("Success to decrypt request param info !")
        LOG.info("Start to deal with function: %s !" % func.__name__)
        return func(self, request, *args, **kwargs)

    return _inner


